#define _GNU_SOURCE
#include "app_device.h"
#include <fcntl.h>
#include "app_buffer.h"
#include "app_pool.h"
#include "app_mqtt.h"
#include "log/log.h"
#include "unistd.h"
#include "app_message.h"
#include "stdlib.h"
#include "app_common.h"

#define BUFFER_SIZE 1024
#define POOL_SIZE 10
#define INTERVAL_TIME_MS 200 //两次写入的最小时间间隔差 
static Device *device = NULL;

Device *app_device_init(char *filename)
{
    if (device)
    {
        return device;
    }
    //申请设备内存
    device = (Device *)malloc(sizeof(Device));
    //设置设备属性
    device->filename = filename;
    device->fd = open(filename, O_RDWR);
    device->up_buffer = app_buffer_init(BUFFER_SIZE);
    device->down_buffer = app_buffer_init(BUFFER_SIZE);
    device->is_running = 0;
    device->post_read = NULL;
    device->pre_write = NULL;
    
    //初始化线程池
    app_pool_init(POOL_SIZE);

    //初始化mqtt
    app_mqtt_init();
    
    return device;
}

//在线程池中某个分线程执行的任务函数
static int send_task_fun(void *arg)
{
    char data_buf[128];
    //从上行缓冲区中读取消息数据
    int len = app_buffer_read(device->up_buffer, data_buf, sizeof(data_buf));
    if (len <= 0)
    {
        log_error("read up_buffer error"); 
        return -1;
    }
    //将字符数组转换为json消息

    char *json = app_message_charsToJson(data_buf, len);

    //将json消息发送到远程服务器

    int result = app_mqtt_send(json);
    if (result == -1)
    {
        log_error("mqtt send error");
        free(json);
        return -1;
    }
    log_debug("mqtt send success");
    free(json);
    return 0;
}

//不断读取串口数据的线程函数
static void *read_thread_fun(void *arg)
{
    while (device->is_running)
    {
        //读取串口数据
        char data_buf[128];
        int len = read(device->fd, data_buf, sizeof(data_buf)); 
        
        if (len > 0 && device->post_read)
        {
            len = device->post_read(data_buf, len);      
            if (len > 0)
            {
                //将字符数组消息保存到上行缓冲区
                app_buffer_write(device->up_buffer, data_buf, len);
                //注册任务  将发送消息到远程的操作交给线程池
                app_pool_registerTask(send_task_fun,NULL);
            }   
        }
    }
}

//由线程池的分线程执行
static int write_task_fun(void *arg)
{
    //从下行缓冲区中读取字符数组消息数据
    char data_buf[128];
    int len = app_buffer_read(device->down_buffer, data_buf, sizeof(data_buf));
    if (len <= 0)
    {
        log_error("read down_buffer error");
        return -1;
    }
    //将字符数组消息转换为传输格式数据消息(蓝牙)
    if (device->pre_write)
    {
        len = device->pre_write(data_buf, len);
       
             if (len > 0)
        {
            //如果没有达到200ms的时间间隔,则等待相差时间
            long interval_time = app_common_getCourrentTime() - device->last_write_time;
            if (interval_time < INTERVAL_TIME_MS)
            {
                usleep((INTERVAL_TIME_MS - interval_time) * 1000);
            }

            //将传输格式数据消息写入串口,发送下游设备
            int write_len = write(device->fd, data_buf, len);
            if (write_len != len)
            {
                log_error("write device error");
                return -1;
            }
            //保存写入的时间
            device->last_write_time = app_common_getCourrentTime();
            log_debug("write device success : %s", app_common_charsToHexstr(data_buf, len));
            return 0;
        }
    }
    return -1;
}

static int receive_msg_callback(char *json)
{
    //将json消息转换为字符数组消息
    char data_buf[128];
    int len = app_message_jsonToChars(json, data_buf, sizeof(data_buf));
    //将字符数据消息写入下行缓冲区
    app_buffer_write(device->down_buffer, data_buf, len);
    //注册任务 : 将后续的操作的线程交给线程池
    app_pool_registerTask(write_task_fun, NULL);

}

int app_device_start(void)
{
    if (device->is_running)
    {
        log_debug("device is running");
        return -1;
    }
    device->is_running = 1;
    //创建读线程
    pthread_create(&device->read_thread, NULL, read_thread_fun, NULL);

    //向mqtt模块注册一个接受远程消息的回调函数
    app_mqtt_registerRecvCallback(receive_msg_callback);

    return 0;
}


void app_device_destroy(void)
{
    close(device->fd);
    
    app_buffer_free(device->up_buffer);
    app_buffer_free(device->down_buffer);
    
    pthread_cancel(device->read_thread);
    device->is_running = 0;
    device->post_read = NULL;
    device->pre_write = NULL;
    
    app_pool_destroy();
    
    app_mqtt_close();
    
}

